<?php
namespace app\index\controller;

use app\index\controller\Cronrecent;
use app\index\model\LLogin;
use app\index\model\LRegister;
use app\index\model\Retention;
use think\Controller;

header("Content-type: text/html; charset=utf-8");

/**
 * 用户留存计算
 */
class Cronret extends Controller
{
    /*
     * 数组
     *
     * '1' 注册用户数，日活跃用户计算
     * '2' 次日留存计算
     * '3' 3日留存
     * '4' 4日留存
     * '5' 5日留存
     * '6' 6日留存
     * '7' 7日留存
     * '15' 15日留存
     * '30' 30日留存
     */
    private $nodes = [1, 2, 3, 4, 5, 6, 7, 15, 30];
    //private $servers = ['1001' => ['opentime' => '2017-11-24 10:32:56']];
    //
    private $servers = ['1' => ['opentime' => '2018-04-09 15:35:10']];
    public function _initialize()
    {
        $this->lregister = new LRegister();
        $this->llogin    = new LLogin();
    }

    /**
     * 留存计算
     *
     * @return   void
     */
    public function doCompute()
    {
        //获取Character、Llogin、Lregister表最新记录
        //
        $this->updateToRecent();

        //最后一天开始顺序计算留存
        //
        //$this->computeToRecent();
        $this->computeFromOpendate();
    }

    /**
     * 获取Character、Llogin、Lregister表最新记录
     *
     * @return   void
     */
    public function updateToRecent()
    {
        $Cronrecent = new Cronrecent();
        $Cronrecent->updateToRecent();
    }

    /**
     * 逆序留存计算
     *
     * @return   void
     */
    public function computeReversed()
    {

        //计算日期
        $calcDate = date('Y-m-d', strtotime("-1 day"));

        //遍历服务器数组

        foreach ($this->servers as $key => $info) {

            $opentime = $info['opentime'];

            //遍历留存计算日期
            foreach ($this->nodes as $day) {

                //留存模型实例化
                $model = new Retention;

                //保存数组
                //
                $res = [];

                //玩家注册日期和开服时间比较,如果注册日期大于开服日期，计算该节点用户留存

                $regDate = date('Y-m-d', strtotime("-" . $day . " day"));

                //开服日期

                $open_date = date("Y-m-d", strtotime($opentime));

                if (strtotime($regDate) >= strtotime($open_date)) {

                    if (1 === $day) {

                        //计算新注册人数及日活跃人数

                        $res['date']     = $regDate;
                        $res['DAU']      = $this->llogin->getDAU($regDate);
                        $res['register'] = $this->lregister->getRegTotal($regDate);
                        $res['total']    = $this->lregister->getRegGrandTotal($regDate);

                        //保存昨天的新注册及日活跃人数

                        $model->isUpdate(false)->save($res);

                    } else if (1 < $day) {

                        //计算注册日期开始，第 $day 天的留存数

                        $res['RET' . $day] = $this->llogin->getRET($regDate, $calcDate);

                        //保存注册日期开始，第 $day 天的留存数

                        $model->isUpdate(true)->save($res, ['date' => $regDate]);
                    }
                }
            }
        }
    }

    /**
     * 顺序计算开服至今的留存率
     *
     * 注意：将会删除开服至今的历史计算数据
     *
     * @return   void
     */
    public function computeToRecent()
    {

        // 留存表计算最近日期
        //
        $Retention = new Retention();
        $recent    = $Retention->getRecentDate();

        // 最近日期 + 1天
        //
        $time = strtotime($recent) + 3600 * 24;

        // 距今最近计算日期
        //
        $compute_date = date('Y-m-d', $time);

        //最近日期非空
        //
        if ($recent) {
            $this->computeInorderFrom($compute_date);
        }
    }

    /**
     * 顺序计算开服至今的留存率
     *
     * 注意：将会删除开服至今的历史计算数据
     *
     * @return   void
     */
    public function computeFromOpendate()
    {

        //开服日期 '2017-11-24','2017-12-25','2018-01-31';
        $opendate = '2018-04-09';

        //闭包删除
        $msg = Retention::destroy(function ($query) use ($opendate) {
            $query->where('date', '>=', $opendate);
        });

        //dump($msg);
        $this->computeInorderFrom($opendate);
    }
    /**
     * 顺序留存计算
     *
     * @return   void
     */
    public function computeInorderFrom($start_date)
    {

        //今天日期

        $today = date("Y-m-d");

        //计算日期差值

        $days = floor((strtotime($today) - strtotime($start_date)) / 86400);

        $rtn = [];

        //计算起始日期至今的留存人数、活跃人数及注册人数

        $begin_time = microtime(true);

        try {

            for ($x = 0; $x < $days; $x++) {

                //保存数组

                $res = [];

                $time    = strtotime($start_date) + 3600 * 24 * $x;
                $regDate = date('Y-m-d', $time);

                //保存日期

                $res['date'] = $regDate;

                $start_time = microtime(true);

                foreach ($this->nodes as $day) {

                    //计算当日注册及活跃
                    //
                    if (1 == $day) {

                        //计算新注册人数、总注册人数及日活跃人数
                        //
                        $res['DAU']      = $this->llogin->getDAU($regDate);
                        $res['register'] = $this->lregister->getRegTotal($regDate);
                        $res['total']    = $this->lregister->getRegGrandTotal($regDate);

                    } else {

                        //计算注册日期第 $day 天的留存率
                        //
                        $calcTime = strtotime($regDate) + 3600 * 24 * ($day - 1);
                        $calcDate = date('Y-m-d', $calcTime);

                        //前提留存计算日期小于今天
                        //
                        if ((strtotime($today) - 3600 * 24) >= $calcTime) {
                            $res['RET' . $day] = $this->llogin->getRET($regDate, $calcDate);
                        } else {
                            $res['RET' . $day] = null;
                        }
                    }

                    $res['create_time'] = date("Y-m-d H:i:s", time());
                }

                array_push($rtn, $res);

                $end_time = microtime(true);

                //echo '循环执行时间：' . ($end_time - $start_time) . ' s';
                //echo '<br />';
            }

            //计算总时间
            $over_time = microtime(true);

            //echo '累计执行时间：' . ($over_time - $begin_time) . ' s';
            //echo '<br />';
            //dump($rtn);

            //保存所有日期节点的留存注册数据以及活跃率数据
            $model = new Retention;
            $model->insertAll($rtn);

            $output['success'] = true;
            $output['msg']     = '完成数据更新';

            _callback($output);

        } catch (\Exception $e) {
            throw new \think\Exception('异常消息:' . $e->getMessage());
        }
    }

}
